import  utils from '../../utils/utils'
let demo =()=>{
  //## 001. 声明变量
  //```
  let text =[];
  var aa1='222222';
  console.log('var是函数作用域,不能访问函数里面的变量,没有函数的话就是全局作用域。');
  if(true){
    let bb1='222222';
    console.log(`let 是块级作用域，当出现{},{}之外就无法访问到具体的变量`);
  }
  const cc1='3333';//定义常量
  //```

  //## 002. 函数的参数 扩展运算符的用法 函数默认值
  //```
  function test2(a,b,...c){
    console.log(a);
    console.log(b);
    console.log(c);
  }
  test2(1,23,4,5,6,3,7,7,22,8)
  
  var aa2=[222,33,444,555]
  var bb2=[33,44,55];
  var cc2=aa2.concat(bb2);
  console.log(cc2);
  //```

  //## 003. 解构赋值 
  //```
  //左右2边结构要一样，右边的结构得成立
  var [aa3,bb3,cc3]=[1,2,3,4];
  console.log(aa3,bb3,cc3);
  var {aa31,bb31}={aa:2222,bb:3333};
  console.log(aa31,bb31);
  //```

  //## 004. 实现一个call call是替换函数的this; 
  //```
  Function.prototype.myCall = function (context) {
    var context = context || window
    // 给 context 添加一个属性
    // getValue.call(a, 'yck', '24') => a.fn = getValue
    context.fn = this
    // 将 context 后面的参数取出来
    var args = [...arguments].slice(1)
    // getValue.call(a, 'yck', '24') => a.fn('yck', '24')
    var result = context.fn(...args)
    // 删除 fn
    delete context.fn
    return result
  }
  //```
  
  //## 005. 如何判断是否是对象 利用原型链
  //``` 
  let aa5 ={name:222};
  console.log(aa5.constructor ===Object);
  //```

  //## 006.说说箭头函数的特点
  //```
  //个人理解：原本的函数区分编译期和执行期，导致执行时候当前的this会发生变化，但是箭头函数不存在这个问题
  //```

  //## 007. async await ,要等await 后面的跟的东西执行完(异步除外),才会执行之后的相关代码
  //```
  let fun71=function(){
    let aa=0;
    for(var ii =0;ii< 1000000000;ii++){
      aa+=ii;
    }
    console.log(aa);
  }
  async function fun7(){
    console.log(111111);
    await fun71();
    console.log(2222222)
  }
  fun7();
  //```

  //## 008 Generator 一种处理异步的一个东西
  //```
  function *fun8(a,b){
    console.log(a);
    yield a;//可以将结果传出来
    console.log(b);
  }
  //通过实例调用
  let aa8=fun8('aa8','bb8');
  console.log(aa8.next());//一次只会执行一部分
  console.log(aa8.next());//一次只会执行一部分
  //```

  //## 009.== 和 ===区别，什么情况用 == 闭包
  //```
  //=== 用于判断两者类型和值是否相同。 在开发中，使用==是不确定类型 希望发生隐式类型转换
  //函数 A 返回了一个函数 B，并且函数 B 中使用了函数 A 的变量，函数 B 就被称为闭包。
  //```

  //## 010.数组降纬
  //```
  // [1, [2], 3].flatMap((v) => v + 1)
  // -> [2, 3, 4]

  //复制代码如果想将一个多维数组彻底的降维，可以这样实现
  const flattenDeep = (arr) => Array.isArray(arr)
  ? arr.reduce( (a, b) => [...a, ...flattenDeep(b)] , [])
  : [arr]

  flattenDeep([1, [[2], [3, [4]], 5]])
  //```

  //## 011. cookie和localSrorage、session、indexDB 的区别
  //```
  //特性	                    cookie	                      localStorage	    sessionStorage	        indexDB
  //数据生命周期	    一般由服务器生成，可以设置过期时间	   除非被清理，否则一直存在	    页面关闭就清理	   除非被清理，否则一直存在
  //数据存储大小	                4K	                            5M	                5M	                无限
  //与服务端通信	每次都会携带在 header 中，对于请求性能影响	          不参与	            不参与	              不参与
  //```

  //## 012. React生命周期
  //```
  // 组件生命周期分为三部分
  // 组件创建阶段：组件生命周期函数一辈子只执行一次
  // componentWillMount：组件将要被挂载，此时还没有开始渲染虚拟 DOM（现在已经更名为UNSAFE_componentWillMount，相对于 Vue 中的 created）
  // render：第一次开始渲染真正的虚拟 DOM，当 render 执行完，内存中就有完整的虚拟 DOM 了
  // componentDidMount：组件完成挂载，此时，组件已经显示到页面上了，当这个方法执行完，组件就都进入了运行中的状态（相对于 Vue 中的mounted）
  // 组件运行阶段：根据组件 state 跟 props 的改变，有选择性的触发0次或者多次
  // componentWillReceiveProps：组件将要接收新属性，此时，只要这个方法被触发，就证明父组件为当前子组件传递了新的属性值（首次并不会触发函数）
  // shouldComponentUpdate：组件是否需要被更新，此时，组件尚未被更新，但是，state 和 props 肯定是最新的
  // componentWillUpdate：组件将要被更新，此时，尚未开始更新，内存中的虚拟 DOM 树还是旧的，页面上的 DOM 树也是旧的
  // componentDidUpdate：此时页面又被重新渲染了， state和虚拟 DOM和页面已经完成保持同步
  // render：此时，又要重新根据最新的 state 和 props 重新渲染一颗内存中的虚拟 DOM 树，当 render 调用完毕，内存中的旧 DOM 树，已经被新 DOM 树替换了，此时页面还是旧的
  // 组件销毁阶段：一辈子只执行一次
  // componentWillUnmount：组件将要被卸载，此时组件还可以正常使用
  
  //具体使用 看这个 https://juejin.im/post/5c92f499f265da612647b754
  class Component {
    // 替换 `componentWillReceiveProps` ，
    // 初始化和 update 时被调用
    // 静态函数，无法使用 this
    static getDerivedStateFromProps(nextProps, prevState) {}
    
    // 判断是否需要更新组件
    // 可以用于组件性能优化
    shouldComponentUpdate(nextProps, nextState) {}
    
    // 组件被挂载后触发
    componentDidMount() {}
    
    // 替换 componentWillUpdate
    // 可以在更新之前获取最新 dom 数据
    getSnapshotBeforeUpdate() {}
    
    // 组件更新后调用
    componentDidUpdate() {}
    
    // 组件即将销毁
    componentWillUnmount() {}
    
    // 组件已销毁
    componentDidUnMount() {}
  }
  //```


  //## 013. JavaScript 中如何检测一个变量是一个 String 类型？
  //```
  // typeof('123') === "string" // true
  // '123'.constructor === String // true
  // Object.prototype.toString.call('123') === '[object String]' // true
  //```


  //## 014.请用 js 去除字符串空格？
  //```
  var aa14='asdasdasd asdasdasdasffff   fff fffffff  ';
  var bb14=aa14.split(' ');
  var cc14='';
  for(let ii of bb14){
    cc14+=ii;
  }
  console.log(cc14);


  var dd14 = aa14.replace(/\s*/g,"");
  //```

  //## 015.事件委托是什么 利用事件冒泡，在父级绑定事件 触发。减少性能损耗

  //## 016.javascript 对象的几种创建方式
  //```
  // var aa16={name:11,age:33}
  // var bb16 =new Object();
  // bb16.name=11;

  // (function(name){
  //   this.name=name;
  //   this.sey=function(){
  //     console.log(33);
  //   }
  // })('22')
  //```

  //## 017.JavaScript 继承的方式和优缺点
  //```
  //1,原型链继承
  //Son.prototype=new Father();
  //2,借助构造函数
  // function Son(name) {
  //   Father.call(this);
  //   this.name = name || '->son';
  // }
  //3,es6 类的继承
  //4,最优方案  圣杯继承
  function Father17(){
    this.name='何三磊'
  }
  function Son17(){
  }

  //要继承的子级
  var inherit = (function(c,p){
    var F = function(){};
    return function(c,p){
      F.prototype = p.prototype;
      c.prototype = new F();
      c.uber = p.prototype;
      c.prototype.constructor = c;
    }
  })();
  
  console.log(Son17);
  console.log(Son17);
  console.log(Son17);
  console.log(Son17);
  //```

  //## 018.冒泡排序
  //```
  // var aaaa=[222,33214,124,1,412421,44214,22,214];
  // for(var ii =0;ii<aaaa.length-1;ii++){
  //   for(var jj =0;jj<aaaa.length-1-ii;jj++){
  //     if(aaaa[jj]<aaaa[jj+1]){continue;}
  //     var aaaa1=aaaa[jj];
  //     aaaa[jj]= aaaa[jj+1];
  //     aaaa[jj+1]=aaaa1;
  //   }

  // }
  // console.log(aaaa);
  //```

  //## 019.高阶组件
  //```
  //简单来说是对一个组件的包装，接收一个组件 然后处理返回一个新的组件。
  //举个实际例子。循环列表：列表父组件包裹整个循环的子列表，父组件 获取循环的数据，循环渲染子组件。
  //不适用场景：根据redux数据判断是显示什么组件（根据登录状态跳转个人中心还是登录）
  //适用场景：给组件追加 新的数据 
  //```
  
  //## 020.数组去重
  //```
  //1 set
  var aa19=[1,23,4,45,234,44,15,44,15,3323];
  // var bb19 =new Set(aa19)
  //2 类似于冒泡排序 依次比较相邻2个是不是相等 相等就剔除
  // for(var ii=0;ii<aa19.length;ii++){
  //   for(var jj=ii+1;jj<aa19.length;jj++){
  //     if(aa19[ii]==aa19[jj]){
  //       aa19.splice(jj,1);
  //       jj--;
  //     }
  //   }
  // }
  //3 循环 每个拿出来和其他对比
  var cc19=[];
  for(var iii of aa19){
    console.log(iii);
    if(cc19.indexOf(iii)==-1){
      console.log(iii+'iii')
      cc19.push(iii);
    }
  }


  
  console.log(cc19);
  //```

  //## 021.js垃圾处理机制
  //```
  // （1）标记清除法
  // 在函数声明一个变量的时候，就将这个变量标记为“进入环境”。从逻辑上讲，永远都不能释放进入环境的变量作占用的内存，因为只要执行流进入相应的环境，就可能会用到它们。而当变量离开环境时，则将其标记为“离开环境”。垃圾回收器在运行时候会给存储在内存中中的所有变量都加上标记。然后它会去掉环境中的变量以及被环境中的变量引用的变量的标记（闭包）。在此之后再被标记的变量将被视为准备删除的变量，原因是环境中的变量已经无法访问到这些变量了。最后，垃圾回收器完成内存清楚工作，销毁那些带标记的值并回收他们所占用的内存空间。
  function
  
  test(){ 
  
  var a = 10 ; //被标记 ，进入环境 
  
  var b = 20 ; //被标记 ，进入环境 
  
  } 
  test(); //执行完毕 之后 a、b又被标离开环境，被回收。
  // （2）引用计数法

  // 引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时，则这个值的引用次数就是1。如果同一个值又被赋给另一个变量，则该值的引用次数加1。相反，如果包含对这个值引用的变量又取得了另外一个值，则这个值的引用次数减1。当这个值的引用次数变成0时，则说明没有办法再访问这个值了，因而就可以将其占用的内存空间回收回来。这样，当垃圾回收器下次再运行时，它就会释放那些引用次数为0的值所占用的内存。

  // 但是很重要的一点是当遇到循环引用的时候，函数的引用次数就不会为0，所以不会被垃圾回收器回收内存，会造成内存泄露。在IE中涉及COM对象，就会存在循环引用的问题。

  function
  
  test(){ 
  
  var a = {} ; //a的引用次数为0 
  
  var b = a ; //a的引用次数加1，为1 
  
  var c =a; //a的引用次数再加1，为2 
  
  var b ={}; //a的引用次数减1，为1 
  
  }
  //```

  //## 022.数组最值
  //```
  //求数组最大值：Math.max.apply(null,arr);
  var arr = [3,43,23,45,65,90];
  var max = Math.max.apply(null,arr);
  console.log(max);
  // 90
  //求数组最小值：Math.min.apply(null,arr);
  var arr = [3,43,23,45,65,90];
  var min = Math.min.apply(null,arr);
  console.log(min);
  // 3
  //```

  console.log('——————————————————————————————————————————');

  //## 024.call实战
  //```
  function Parent(age){
    this.name = ['mick','mini','so']
    this.age = age;
  }

  function children(){
    Parent.call(this,'222');//第二个参数是给父级的参数
    console.log(this.name);
    console.log(this.age);
  }
  //children();
  //```

  //## 025.防抖 节流
  //```
  //1,个人版本
  let time25;
  let fun25=()=>{
    if(time25){
      clearTimeout(time25);
    }else{
      time25=setTimeout(() => {
        console.log('点击了按钮');
      },1000)
    }
  }
  //2,严谨版本 提取了公共版本
  var debounce=function(fn, wait){
    var timer = null;
      return function(){
          if(timer!== null){clearTimeout(timer)};        
          timer= setTimeout(fn, wait);    
      }
  };
  function yourfunc(){
    console.log(Math.random())
  };
  window.addEventListener('click',debounce(yourfunc,2000));
  //3,分流 节流是规定函数在指定的时间间隔内只执行一次，一般用于scroll事件。
  function throttle(fn,time){
    let canRun = true;
    return function(){
        if(!canRun){
            return
        }
        canRun = false;
        setTimeout(() => {
            fn.apply(this,arguments);
            canRun = true;
        },time)
    }
  }
  //```

  //## 026.个人React源码理解
  //```
  //1,核心代码 ReactDOM.render(); 通过babel编译器将，类组件函，数组件，html代码转换为JSX对象。{tag,attrs,children}
  //格式。render函数根据传来的第一个参数 类型做不同的处理。创建出不同节点实例。最后挂载到第二个参数。中途涉及到了新旧节点的对比。
  //2,diff算法：对比新旧节点的变化。第一次渲染,直接新节点替换旧节点。新旧节点对比都转换为JSX对比，第三个参数用个数组接收。循环对比子节点数组的变化。
  //创建子节点的时候的时候会给节点加个id。如果子节点id相同 替换属性。没有就根据下标替换。遍历这个比较子级节点的变化。到最后每个节点点遍历一遍。生成一个新的完整节点
  //2,setState() 会经对state进行diff，判断是否有改变，然后去diff dom决定是否要更新UI。如果这一系列过程立刻发生在每一个setState之后，就可能会有性能问题。
  //在短时间内频繁setState。React会将state的改变压入栈中，在合适的时机，批量更新state和视图，达到提高性能的效果。

  // react原理:
  // Virtual Dom模型
  // 生命周期管理
  // setState机制
  // diff算法
  // React patch、事件系统
  // react的 Virtual Dom模型
  
  // React diff 原理
  // (1) 把树形结构按照层级分解，只比较同级元素。
  // (2) 列表结构的每个单元添加唯一的 key 属性，方便比较。
  // (3) React 只会匹配相同 class 的 component（这里面的 class 指的是组件的名字）
  // (4) 合并操作，调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
  // (5) 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。

  //```

  //### 027. React.PureComponent React.memo
  //```
  // React.PureComponent 内部实现了shouldComponentUpdate();会对props浅比较，
  //也就是说，如果是引用类型的数据，只会比较是不是同一个地址，而不会比较具体这个地址存的数据是否完全一致
  //来判断是非重新渲染
  //React.memo() 是纯函数的实现,功能和React.PureComponent 优化性能
  //```

  //### 028. setState的同步实现
  //```
  // React 为了优化性能，有可能会将多个 setState() 调用合并为一次更新。
  // 因为this.props和this.state 可能是异步更新的，你不能依赖他们的值计算下一个state(状态)。以下面的代码为例:

  // this.setState({
  //   counter: this.state.counter + this.props.increment,
  // });
  // 我们并不能通过上述代码得到想要的值，为了弥补这个问题，使用另一种 setState() 的形式，接受一个函数。这个函数将接收前一个状态作为第一个参数，应用更新时的 props 作为第二个参数，代码如下：

  // this.setState((prevState, props) => ({
  //   counter: prevState.counter + props.increment
  // }));
  //```
  //### 029.React.memo优化 第二个参数返回true不会渲染
  //```
  // memo优化策略 areEqual 返回true就不会重新渲染
  // function areEqual(prevProps: Props, nextProps: Props) {
  //   return (
  //     prevProps.checked === nextProps.checked
  //   )
  // }

  // const ItemCard: FC<Props> = React.memo(props => {
  //   const { checked, onCheckedChange } = props
  //   return (
  //     <div>
  //       <checkbox 
  //         value={checked} 
  //         onChange={(value) => onCheckedChange(cartItem, value)} 
  //       />
  //       <span>商品</span>
  //     </div>
  //   )
  // }, areEqual)
  //```


  // React 原理
}
export default demo;